package com.xuecheng.media.infrastructure.util;

import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.media.infrastructure.constant.VideoConstant;
import com.xuecheng.media.infrastructure.enums.VideTypeEnum;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: LiJunXi
 * @Description: 视频转码工具类
 * @Date: 2024-08-10  10:32
 */
@Slf4j
public class VideoUtil {

    private String savePath;
    private String filePath;

    public VideoUtil(String filePath, String filename, VideTypeEnum videTypeEnum){
        this.savePath = VideoConstant.savePath + "\\" + filename + "." + videTypeEnum.getType();
        this.filePath = filePath;
    }

    /**
     * 清除文件
     * @param filePath
     */
    public void clearFile(String filePath){
        File file = new File(filePath);
        if (file.exists() && file.isFile()){
            file.delete();
        }
    }

    /**
     * 获取执行命令
     * ffmpeg.exe -i  lucene.avi -c:v libx264 -s 1280x720 -pix_fmt yuv420p -b:a 63k -b:v 753k -r 18 .\lucene.mp4
     * @param filePath
     * @return
     */
    public List<String> getCommands(String filePath, String savePath){
        List<String> commend = new ArrayList<>();
        commend.add(VideoConstant.ffmpegPath);
        commend.add("-i");
        commend.add(filePath);
        commend.add("-c:v");
        commend.add("libx264");
        commend.add("-y");//覆盖输出文件
        commend.add("-s");
        commend.add("1280x720");
        commend.add("-pix_fmt");
        commend.add("yuv420p");
        commend.add("-b:a");
        commend.add("63k");
        commend.add("-b:v");
        commend.add("753k");
        commend.add("-r");
        commend.add("18");
        commend.add(savePath);
        return commend;
    }

    /**
     * 转码成给定的视频格式
     * @return
     */
    public String generate(){
        // 清除以前已经生成的
        clearFile(savePath);
        // 获取执行命令
        List<String> commands = getCommands(filePath, savePath);
        String outString = "error";
        try {
            ProcessBuilder processBuilder = new ProcessBuilder();
            processBuilder.command(commands);
            Process process = processBuilder.start();
//            outString = waitFor(process);
        } catch (Exception e){
            log.error("执行视频转码命令出错，原因：{}", e.getMessage());
        }

        Boolean check = checkVideoTime(filePath, savePath);
        return !check ? outString : "success";
//        return "success";
    }


    public String waitFor(Process p) {
        InputStream in = null;
        InputStream error;
        String result = "error";
        int exitValue = -1;
        StringBuffer outputString = new StringBuffer();
        try {
            in = p.getInputStream();
            error = p.getErrorStream();
            boolean finished = false;
            int maxRetry = 600;// 每次休眠1秒，最长执行时间10分种
            int retry = 0;
            while (!finished) {
                if (retry > maxRetry) {
                    return result;
                }
                try {
                    while (in.available() > 0) {
                        Character c = new Character((char) in.read());
                        outputString.append(c);
                        log.info("" + c);
                    }
                    while (error.available() > 0) {
                        Character c = new Character((char) in.read());
                        outputString.append(c);
                        log.info("" + c);
                    }
                    // 进程未结束时调用exitValue将抛出异常
                    exitValue = p.exitValue();
                    finished = true;
                } catch (IllegalThreadStateException e) {
                    Thread.currentThread().sleep(1000); //休眠1秒
                    retry++;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
        return outputString.toString();
    }

    /**
     * 检查视频时间是否一致
     * @param source
     * @param target
     * @return
     */
    public Boolean checkVideoTime(String source, String target) {
        String sourceTime = getVideoTime(source);
        //取出时分秒
        sourceTime = sourceTime.substring(0, sourceTime.lastIndexOf("."));
        String targetTime = getVideoTime(target);
        //取出时分秒
        targetTime = targetTime.substring(0, targetTime.lastIndexOf("."));
        if(sourceTime == null || targetTime == null){
            return false;
        }
        if(sourceTime.equals(targetTime)){
            return true;
        }
        return false;
    }

    /**
     * 获取视频时间(时：分：秒：毫秒)
     * @param videPath
     * @return
     */
    public String getVideoTime(String videPath) {
        /*
        ffmpeg -i  lucene.mp4
         */
        List<String> commend = new ArrayList<>();
        commend.add(VideoConstant.ffmpegPath);
        commend.add("-i");
        commend.add(videPath);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
            // 将标准输入流和错误输入流合并，通过标准输入流程读取信息
            builder.redirectErrorStream(true);
            Process p = builder.start();
            String outstring = waitFor(p);
            int start = outstring.trim().indexOf("Duration: ");
            if(start>=0){
                int end = outstring.trim().indexOf(", start:");
                if(end>=0){
                    String time = outstring.substring(start+10,end);
                    if(time!=null && !time.equals("")){
                        return time.trim();
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

}
